package com.example.demo.controllerAdvice;

import cn.dev33.satoken.exception.*;
import cn.dev33.satoken.stp.StpUtil;
import com.example.demo.annotation.IgnoreResponseAdvice;
import com.example.demo.util.AjaxJson;
import com.example.demo.util.CustomException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Slf4j
@RestControllerAdvice("com.example.demo.controllerApi")
//@Order(Ordered.HIGHEST_PRECEDENCE)
public class GlobalExceptionHandlerForApi implements ResponseBodyAdvice {


    @Override
    public boolean supports(MethodParameter methodParameter, Class aClass) {
        //通过方法参数得到类名， 然后得到类上的annotation，
        // 如果被IgnoreResponseAdvice标识就不拦截
        if (methodParameter.getDeclaringClass().isAnnotationPresent(
                IgnoreResponseAdvice.class
        )) {
            return false;
        }

        //方法上被标注，也不拦截
        if (methodParameter.getMethod().isAnnotationPresent(
                IgnoreResponseAdvice.class
        )) {
            return false;
        }
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        return null;
    }

//    // 在当前类每个方法进入之前触发的操作
//    @ModelAttribute
//    public void get(HttpServletRequest request) throws IOException {
//
//    }

    // 全局异常拦截（拦截项目中的所有异常）
    @ExceptionHandler
    public AjaxJson handlerExceptions(Exception e, HttpServletRequest request, HttpServletResponse response) {

        // 打印堆栈，以供调试
        log.info("全局异常(API)---------------");
        log.info(request.getRequestURL() + "?" + request.getQueryString());
        e.printStackTrace();

        String errPre = "Failure: ";

        // 不同异常返回不同状态码
        AjaxJson aj;
        if (e instanceof NotLoginException) {               // 如果是未登录异常
            NotLoginException ee = (NotLoginException) e;
            aj = AjaxJson.getNotLogin(errPre + "未登录：" + ee.getMessage());
        } else if (e instanceof NotRoleException) {         // 如果是角色异常
            NotRoleException ee = (NotRoleException) e;
            aj = AjaxJson.getNotJur(errPre + "无此角色：" + ee.getRole());
        } else if (e instanceof NotPermissionException) {   // 如果是权限异常
            NotPermissionException ee = (NotPermissionException) e;
            aj = AjaxJson.getNotJur(errPre + "无此权限：" + ee.getCode());
        } else if (e instanceof DisableLoginException) {    // 如果是被封禁异常
            DisableLoginException ee = (DisableLoginException) e;
            aj = AjaxJson.getNotJur(errPre + "账号被封禁：" + ee.getDisableTime() + "秒后解封");
        } else if (e instanceof NotSafeException) {         // 如果是二级认证
            NotSafeException ee = (NotSafeException) e;
            log.info("二级认证异常：" + ee.getMessage());
            StpUtil.openSafe(120);
            aj = AjaxJson.getNotJur(errPre + "二级认证：请于120秒内进行二级认证后重新访问");
        } else if (e instanceof CustomException) {
            aj = AjaxJson.getError(errPre + e.getMessage());
        } else {    // 普通异常, 输出：500 + 异常信息
            aj = AjaxJson.getError(errPre + e.getMessage());
        }

        // 返回给前端
        return aj;

        // 输出到客户端
//		response.setContentType("application/json; charset=utf-8"); // http说明，我要返回JSON对象
//		response.getWriter().print(new ObjectMapper().writeValueAsString(aj));
    }

}
